interface IDetectParams {
  /**
   * 是否开启版本检测， 为true开启检测
   */
  open: boolean;
  //静态资源前缀
  path?: string;
  /**
   * 轮询查询间隔 单位ms 默认每五秒进行一次比对
   */
  duration?: number;
  /**
   * 检测到版本更新后的执行回调,如果不传 默认执行提示弹窗
   */
  func?: () => void;
}

const defaultFunc = () => {
  const result = confirm("有新功能发布，请点击确定刷新页面！");
  if (result) {
    location.reload(); //强制刷新 清除缓存
  }
};

const detectVersion = ({
  open,
  path = "/",
  duration = 5000,
  func = defaultFunc,
}: IDetectParams) => {
  if (path && typeof path !== "string") throw new Error("open must be string");
  if (typeof open !== "boolean") throw new Error("open must be boolean");
  if (typeof duration !== "number") throw new Error("duration must be number");
  if (typeof func !== "function") throw new Error("func must be function");

  if (!open) return;
  // 发版刷新页面，根据监测上传文件实现刷新
  //定义local存储key
  const key = "version";

  //获取到js名字
  const scriptReg = /\<script.*src=["'](?<src>[^"']+)/gm;

  //获取最新页面中的script链接
  async function extractNewScripts() {
    // _timestamp避免缓存，获取当前时间戳
    const html = await fetch(path + "?_timestamp=" + Date.now()).then((resp) =>
      resp.text()
    );

    scriptReg.lastIndex = 0;
    let result: string[] = [];

    let match;
    while ((match = scriptReg.exec(html))) {
      result.push(match.groups?.src!);
    }

    return result;
  }

  //进行js文件命名对比
  async function needUpdate() {
    const newScripts = await extractNewScripts();
    const oldScripts = getLocal(key)?.split(",");
    if (!oldScripts) {
      setLocal(key, newScripts);
      return false;
    }

    let result = false;
    if (oldScripts.length !== newScripts.length) {
      result = true;
    }
    for (let i = 0; i < oldScripts.length; i++) {
      if (oldScripts[i] !== newScripts[i]) {
        result = true;
        break;
      }
    }
    setLocal(key, newScripts);
    return result;
  }

  //轮询检测
  const autoRefresh = () => {
    updated(); //先执行一次

    setTimeout(async () => {
      updated();
      autoRefresh();
    }, duration);
  };

  // 更新版本处理
  const updated = async () => {
    const willUpdate = await needUpdate();
    if (willUpdate) {
      // 发现有新版本 执行对应方法
      if (func && typeof func == "function") return func();
      // 不然执行默认方法
      defaultFunc();
    }
  };

  // 取出
  const getLocal = (key: string) => {
    return localStorage.getItem(key);
  };
  // 存储
  const setLocal = (key: string, value: any) => {
    localStorage.setItem(key, value);
  };

  autoRefresh();
};

export default detectVersion;
